package com.example.demo.Util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * @ClassName HttpUtils
 * @Description: http和http请求
 * @Author gss
 * @Date 2021/9/23 10:13
 * @Version V1.0
 **/
@Slf4j
public class HttpUtils {

    /**
     * 连接超时时间
     */
    private static final int HTTP_TIMEOUT_CONNECT = 20000;
    /**
     * 数据传输超时时间
     */
    private static final int HTTP_TIMEOUT_REQUEST = 60000;

    private static final String HTTP = "http";
    private static final String HTTPS = "https";
    private static SSLConnectionSocketFactory sslsf = null;
    private static PoolingHttpClientConnectionManager cm = null;

    private static TrustManager manager = new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    static {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{manager}, null);
            sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register(HTTP, new PlainConnectionSocketFactory())
                    .register(HTTPS, sslsf)
                    .build();
            cm = new PoolingHttpClientConnectionManager(registry);
            cm.setMaxTotal(200);//max connection
        } catch (Exception e) {
            log.error("http初始化异常：", e);
        }
    }

    /**
     * http post请求
     *
     */
    public static String httpPost(String url, Map<String, Object> header, String body) {
        String result = "";
        HttpEntity entity = null;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            config(httpPost);
            // 构造消息头
            if (null != header) {
                Iterator iter = header.entrySet().iterator();
                Map.Entry<String, String> entry = null;
                while (iter.hasNext()) {
                    entry = (Map.Entry) iter.next();
                    httpPost.setHeader(entry.getKey(), entry.getValue().toString());
                }
            }
            if(StringUtils.isNotBlank(body)) {
                httpPost.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
            }
            httpClient = getHttpClient();
            // 执行请求操作，并拿到结果（同步阻塞）
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            // 获取结果实体
            entity = response.getEntity();
            String resContent = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            if (statusCode == HttpStatus.SC_OK) {
                // 按指定编码转换结果实体为String类型
                result = resContent;
            } else {
                log.error("调用系统外部接口服务出错：错误码：{}, 返回报文：{}", statusCode, resContent);
            }
        } catch (Exception e) {
            log.error("调用系统外部接口服务发生异常，异常原因：", e);
        } finally {
            // 释放链接
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
                // 把entity fully consume掉，否则连接池中的connection就会一直处于占用状态
                EntityUtils.consume(entity);
            } catch (IOException e) {
                log.error("http释放资源异常：", e);
            }
        }
        return result;
    }

    /**
     * http GET请求
     *
     */
    public static String httpGet(String url, Map<String, String> header, Map<String,String> params) {
        String result = "";
        HttpEntity entity = null;
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            HttpGet httpGet = null;
            if(MapUtils.isEmpty(params)) {
                httpGet = new HttpGet(url);
            }else{
                httpGet = new HttpGet(url+buildUrl(params));
            }
            config(httpGet);
            // 构造消息头
            if (null != header) {
                Iterator iter = header.entrySet().iterator();
                Map.Entry<String, String> entry = null;
                while (iter.hasNext()) {
                    entry = (Map.Entry) iter.next();
                    httpGet.setHeader(entry.getKey(), entry.getValue().toString());
                }
            }
            httpClient = getHttpClient();
            // 执行请求操作，并拿到结果（同步阻塞）
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            // 获取结果实体
            entity = response.getEntity();
            String resContent = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            if (statusCode == HttpStatus.SC_OK) {
                // 按指定编码转换结果实体为String类型
                result = resContent;
            } else {
                log.error("调用系统外部接口服务出错：错误码：{}, 返回报文：{}", statusCode, resContent);
            }
        } catch (Exception e) {
            log.error("调用系统外部接口服务发生异常，异常原因：", e);
        } finally {
            // 释放链接
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
                // 把entity fully consume掉，否则连接池中的connection就会一直处于占用状态
                EntityUtils.consume(entity);
            } catch (IOException e) {
                log.error("http释放资源异常：", e);
            }
        }
        return result;
    }

    /**
     * http模拟form表单提交
     */
    public static String httpsPostForm(String url, Map<String, String> header, Map<String, String> params) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        String result = "";
        HttpEntity entity = null;
        try {
            // 创建HttpPost请求
            HttpPost httpPost = new HttpPost(url);
            config(httpPost);
            if (header != null) {
                for (Map.Entry<String, String> entry : header.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            List<NameValuePair> paramList = new ArrayList<>();
            if (params != null) {
                for (String key : params.keySet()) {
                    paramList.add(new BasicNameValuePair(key, params.get(key)));
                }
                UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramList, StandardCharsets.UTF_8);
                //模拟表单
                httpPost.setEntity(urlEncodedFormEntity);
            }
            httpClient = getHttpClient();
            // 执行请求操作，并拿到结果（同步阻塞）
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            // 获取结果实体
            entity = response.getEntity();
            String resContent = EntityUtils.toString(entity, "utf-8");
            if (statusCode == HttpStatus.SC_OK) {
                // 按指定编码转换结果实体为String类型
                result = resContent;
            } else {
                log.error("调用系统外部接口服务出错：错误码：{}, 返回报文：{}", statusCode, resContent);
            }
            //释放资源
            EntityUtils.consume(entity);
        } catch (Exception e) {
            log.error("http请求异常：", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("http释放资源异常：", e);
            }
        }
        return result;
    }

    /**
     * 构造get请求的参数
     *
     * @return
     */
    private static String buildUrl(Map<String, String> map) {
        if (MapUtils.isEmpty(map)) {
            return "";
        }
        StringBuffer stringBuffer = new StringBuffer("?");
        for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
            stringBuffer.append(stringStringEntry.getKey()).append("=").append(stringStringEntry.getValue()).append("&");
        }
        String result = stringBuffer.toString();
        if (StringUtils.isNotEmpty(result)) {
            //去掉结尾的&连接符
            result = result.substring(0, result.length() - 1);
        }
        return result;
    }


    /**
     * http请求配置，包括header信息以及超时时间
     *
     * @param httpRequestBase
     */
    private static void config(HttpRequestBase httpRequestBase) {
        // 配置请求的超时设置
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(HTTP_TIMEOUT_CONNECT)
                .setConnectTimeout(HTTP_TIMEOUT_CONNECT)
                .setSocketTimeout(HTTP_TIMEOUT_REQUEST)
                .setRedirectsEnabled(true)
                .build();
        httpRequestBase.setConfig(requestConfig);
    }

    /**
     * 获取httpClient连接
     */
    public static CloseableHttpClient getHttpClient() throws Exception {
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                .setConnectionManager(cm)
                .setConnectionManagerShared(true)
                .build();
        return httpClient;
    }


    public static void main(String [] args){
        Map<String,String> params = new HashMap<String,String>(){{
           put("client_id","e57b7108-4fcc-4d70-ad64-a261a35b31ab");
           put("client_secret","1850c2be-4e10-4e53-b13a-6bdb00022ee7");
            put("grant_type","client_credentials");
        }};

        System.out.println(HttpUtils.httpGet("http://59.203.98.11:8081/BZSOA/rest/oauth2/token",null,params));
    }

}
